/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.datalayer.daoimpl;

import cz.fi.muni.diplomka.common.enumeration.ResearchType;
import cz.muni.fi.diplomka.datalayer.dao.ResearchInProgressDao;
import cz.muni.fi.diplomka.datalayer.entity.ResearchInProgressEntity;
import cz.muni.fi.diplomka.datalayer.util.DbConnector;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.graphdb.Transaction;

/**
 *
 * @author Jakub Kutil
 */
public class ResearchInProgressDaoImpl implements ResearchInProgressDao {

    @Override
    public void addResearchInProgress(ResearchInProgressEntity researchInProgressEntity) {
        if (researchInProgressEntity == null) {
            throw new IllegalArgumentException("Research In Progress Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("playerId", researchInProgressEntity.getPlayerId());
            params.put("researchType", researchInProgressEntity.getResearchType().toString());
            params.put("timeOfFinish", researchInProgressEntity.getTimeOfFinish().getTime());

            String query = "MATCH (Player:Player {id : {playerId}}) "
                    + "CREATE (ResearchInProgress: ResearchInProgress {researchType : {researchType}, timeOfFinish : {timeOfFinish}})"
                    + "<-[r:RESEARCHES]-(Player)";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public void editResearchInProgress(ResearchInProgressEntity researchInProgressEntity) {
        if (researchInProgressEntity == null) {
            throw new IllegalArgumentException("Research In Progress Entity can not be null.");
        }

        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("playerId", researchInProgressEntity.getPlayerId());
            params.put("researchType", researchInProgressEntity.getResearchType().toString());
            params.put("timeOfFinish", researchInProgressEntity.getTimeOfFinish().getTime());

            String query = "MATCH (Player{id : {playerId} })-[r:RESEARCHES]->(ResearchInProgress:ResearchInProgress { researchType : {researchType}})"
                    + " SET ResearchInProgress.timeOfFinish = {timeOfFinish}";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public void deleteResearchInProgress(Long playerId, ResearchType researchType) {
        if (playerId == null) {
            throw new IllegalArgumentException("Player Id can not be null.");
        }
        if (researchType == null) {
            throw new IllegalArgumentException("Research Type can not be null.");
        }
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();

        try (Transaction t = gds.beginTx()) {

            Map<String, Object> params = new HashMap<>();

            params.put("playerId", playerId);
            params.put("researchType", researchType.toString());

            String query = "MATCH (Player:Player{ id : {playerId}})-[r:RESEARCHES]->"
                    + "(ResearchInProgress:ResearchInProgress {researchType : {researchType}})"
                    + "DELETE ResearchInProgress,r";
            engine.execute(query, params);
            t.success();
        }
    }

    @Override
    public List<ResearchInProgressEntity> getAllResearchsInProgressForPlayer(Long playerId) {
        if (playerId == null) {
            throw new IllegalArgumentException("Player Id can not be null.");
        }
        List<ResearchInProgressEntity> researchList = new ArrayList<>();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {
            Map<String, Object> params = new HashMap<>();

            params.put("playerId", playerId);

            String query = "MATCH (Player:Player{ id : {playerId}})-[r:RESEARCHES]->(ResearchInProgress:ResearchInProgress) RETURN ResearchInProgress";
            ExecutionResult result = engine.execute(query, params);
            Iterator<Node> researches = result.columnAs("ResearchInProgress");
            while (researches.hasNext()) {
                Node node = researches.next();

                ResearchInProgressEntity researchInProgressEntity = new ResearchInProgressEntity();
                researchInProgressEntity.setPlayerId(playerId);
                researchInProgressEntity.setResearchType(ResearchType.valueOf(node.getProperty("researchType").toString()));
                researchInProgressEntity.setTimeOfFinish(new Timestamp(Long.valueOf(node.getProperty("timeOfFinish").toString())));

                researchList.add(researchInProgressEntity);
            }
            t.success();
        }

        return researchList;
    }

    @Override
    public List<ResearchInProgressEntity> getAllResearchsInProgress() {
        List<ResearchInProgressEntity> researchList = new ArrayList<>();
        GraphDatabaseService gds = DbConnector.getDBConnection();
        ExecutionEngine engine = DbConnector.getEngine();


        try (Transaction t = gds.beginTx()) {
            Map<String, Object> params = new HashMap<>();

            String query = "MATCH (Player:Player)-[r:RESEARCHES]->(ResearchInProgress:ResearchInProgress) RETURN ResearchInProgress,Player.id";
            ExecutionResult result = engine.execute(query, params);
            ResourceIterator<Map<String, Object>> researches = result.iterator();

            while (researches.hasNext()) {
                Map<String, Object> row = researches.next();
                Node node = (Node) row.get("ResearchInProgress");

                ResearchInProgressEntity researchInProgressEntity = new ResearchInProgressEntity();
                researchInProgressEntity.setPlayerId(new Long(row.get("Player.id").toString()));
                researchInProgressEntity.setResearchType(ResearchType.valueOf(node.getProperty("researchType").toString()));
                researchInProgressEntity.setTimeOfFinish(new Timestamp(Long.valueOf(node.getProperty("timeOfFinish").toString())));

                researchList.add(researchInProgressEntity);
            }
            t.success();
        }
        return researchList;
    }
}
